#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include "cJSON.h"
 
#define N 4096
void *new_sock(void *arg)//建立tcp连接
{
    printf("will recv new connect\n");
    int sockfd, qtfilefd;
    char buf[4096];
    int addrlen = sizeof(struct sockaddr);
    struct sockaddr_in addr, clientaddr;

    // 1创建一个套接字--socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        
        pthread_exit(NULL); // 退出当前线程
    }
 
    // 2定义套接字地址--sockaddr_in
    bzero(&addr, addrlen);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;//虚拟机地址
    addr.sin_port = htons(8001); //新的连接用8001端口
 
    // 3绑定套接字--bind
    if (bind(sockfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind error");
         pthread_exit(NULL); // 退出当前线程
    }
 
    // 4启动监听--listen
    if (listen(sockfd, 5) < 0)
    {
        perror("listen error");
         pthread_exit(NULL); // 退出当前线程
    }
 
    // 5接收连接--accept
    qtfilefd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen);
    if (qtfilefd < 0)
    {
        perror("accept error");
         pthread_exit(NULL); // 退出当前线程
    }
    //第二个tcp接收到QT链接
    printf("recv qt client\n");
 
    // 6收发点表--recv/send
    bzero(buf, 4096);
    if (recv(qtfilefd, buf, 4096, 0) > 0)//从qtfilefd接收数据到buf中
    {
        printf("copy....\n");
        //拷贝配置文件
        int fd = open("/home/hq/node.json", O_WRONLY | O_CREAT | O_TRUNC, 0777);//注意这里路径改成和大家相同的
        if (fd < 0)
        {
            perror("open error");
            pthread_exit(NULL); // 退出线程
        }
        write(fd, buf, 4096);//将buf中的数据拷贝到打开的文件中
         close(fd);
        printf("copy success!\n");
    }
    else
    {
        perror("copy error\n");
    }
    pthread_exit(NULL);//线程结束
}
int main(int argc, char const *argv[])
{
    int broadfd;//广播文件描述符
 
    //创建一个socket文件描述符
    broadfd = socket(AF_INET, SOCK_DGRAM, 0);//创建 UDP 套接字并绑定
    if (broadfd < 0)
    {
        perror("sock error");
        return -1;
    }
    //绑定套接字(ip+port)
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8887); //端口号
    addr.sin_addr.s_addr = INADDR_ANY;//接受来自qt的广播地址
 
    int addrlen = sizeof(addr);
 
    if (bind(broadfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind error");
        return -1;
    }

    ssize_t len;
    char buf[N] = {0};
    struct sockaddr_in cliaddr;//获取发送方的地址
 
    //接收"group2"搜索包
    bzero(buf, N);
    len = recvfrom(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);
 
    //判断是否是本公司产品：收到的数据是否"group2"
    if (strcmp(buf, "group2") != 0)
    {
        printf("not my group\n");
        return -1;
    }
 
    //回复yes，告诉软件，我收到了搜索协议，并且回复地址
    sendto(broadfd, "yes", 4, 0, (struct sockaddr *)&cliaddr, addrlen);
    bzero(buf, N);
 
    //变身为TCP服务器，准备接收软件的升级文件
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpfd < 0)
    {
        perror("sock error");
        return -1;
    }
 
    if (bind(tcpfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind error");
        return -1;
    }
 
    //监听套接字
    if (listen(tcpfd, 5) < 0)
    {
        perror("listen error");
        return -1;
    }
 
    //接收客户端的连接
    printf("wait qt connect\n");
    int clientfd;
 
    //接收对端的地址
    clientfd = accept(tcpfd, NULL, NULL);
    if (clientfd < 0)
    {
        perror("accept error");
        return -1;
    }
 
    //接收到QT端链接
    printf("qt cononect coming\n");
 
    send(clientfd, "yes", 3, 0);
    // bzero(buf, N);
    // recv(clientfd, buf, 4, 0);
    // printf("%s\n", buf);
    while (1)//建立长连接后的连续交互
    {
        bzero(buf, N);
        int len = recv(clientfd, buf, N, 0);
        cJSON *root = cJSON_Parse(buf);//解析接收到的 JSON 数据，得到 cJSON 类型的根节点 root
        cJSON *item = cJSON_GetObjectItem(root, "type");//获取名为 "type" 的节点
        int type = item->valueint;//转换为整型
        if (type == 1)
        {
            printf("TCP链接成功\n");
            pthread_t tid;
            if(pthread_create(&tid, NULL, new_sock, NULL)!=0)//调用 new_sock 线程函数来处理新的网络连接相关操作
            {
                 perror("pthread_create error");
            }
        }
        else if (type == 3)//心跳包
        {
            if (send(clientfd, "living", 7, 0) < 0)
            {
                perror("send error\n");
            }
        }
    }
    return 0;
}